"use strict";

var user = require.main.require("./src/user"),
  db = require.main.require("./src/database"),
  meta = require.main.require("./src/meta"),
  winston = require("winston"),
  loggedIn = require.main.require("connect-ensure-login");

var plugin = {};

var log = {
  info: function(msg) {
    winston.info("[BMA] " + msg);
  },
  warn: function(msg) {
    winston.warn("[BMA] " + msg);
  }
};

plugin.addMobileVerify = function(params, callback) {
  const mobileField = {
    label: "手机号",
    html:
      '<input class="form-control" name="mobile" id="mobile" placeholder="请输入手机号" /><span class="register-feedback" id="mobile-notify"></span><span class="help-block">仅用于验证身份，不对外公开</span>'
  };
  const codeField = {
    label: "验证码",
    html:
      '<input class="form-control" name="code" id="code" placeholder="请输入短信验证码" style="width:auto;display:inline-block" /><input type="button" id="code-button" class="btn btn-primary" data-action="getCode" value="获取验证码" style="margin-left:20px;" /><span class="register-feedback" id="code-notify"></span>'
  };

  if (
    params.templateData.regFormEntry &&
    Array.isArray(params.templateData.regFormEntry)
  ) {
    params.templateData.regFormEntry.push(mobileField);
    params.templateData.regFormEntry.push(codeField);
  } else {
    params.templateData.captcha = [mobileField, codeField];
  }
  callback(null, params);
};

plugin.checkRegister = function(params, callback) {
  const req = params.req;
  const mobile = req.body.mobile;
  if (!mobile) {
    callback({ source: "mobile", message: "必须绑定手机" }, params);
    return;
  }
  plugin.getMobiles(function(err, data) {
    if (data.indexOf(mobile) >= 0) {
      callback({ source: "mobile", message: "手机号已绑定" }, params);
      return;
    }
    const aliSmsCache = req.app.locals.aliyunsms_verify;
    const code = req.body.code;
    const result = plugin.checkVerifyCode(aliSmsCache, mobile, code);
    if (result.error) {
      callback({ source: "code", message: result.info }, params);
    } else {
      callback(null, params);
    }
  });
};

plugin.createdUser = function(params) {
  const uid = params.user.uid;
  const mobile = params.data.mobile;
  db.setObjectField("aliyunsms-verify:uid:mobile", uid, mobile, function(err) {
    if (err == null) {
      user.setUserField(uid, "email:confirmed", 1);
      db.sortedSetRemove("users:notvalidated", uid);
      log.info("User " + uid + " now bind with " + mobile);
    } else {
      log.warn("DB Error " + err);
    }
  });
};

plugin.deleteUserData = function(data, callback) {
  const uid = data.uid;
  plugin.delete(uid, function(err) {
    if (err == null) {
      log.info("User id:" + uid + " 手机已解绑定");
      callback(null, uid);
    } else {
      log.warn("DB Error " + err);
      callback(err);
    }
  });
};

plugin.sentVerifySms = function(req, res) {
  const aliSmsCache = req.app.locals.aliyunsms_verify;
  const mobile = req.body.mobile;
  const uid = req.body.uid;
  const ip = req.ip;
  if (!plugin.canSent(aliSmsCache, uid, mobile, ip)) {
    res.json({ error: true, info: "重复次数过多，1小时后再试" });
    return;
  }

  plugin.updateUserTimes(aliSmsCache, uid);
  plugin.updateMobileTimes(aliSmsCache, mobile);
  plugin.updateUserTimes(aliSmsCache, ip);

  meta.settings.get("aliyunsms-verify", function(err, settings) {
    const Core = require("@alicloud/pop-core");
    var client = new Core({
      accessKeyId: settings.accessKeyId,
      accessKeySecret: settings.accessSecret,
      endpoint: settings.endpoint || "https://dysmsapi.aliyuncs.com",
      apiVersion: "2017-05-25"
    });

    let code = aliSmsCache[mobile + "code"];
    if (!code) {
      code = parseInt(Math.random() * (9999 - 1000) + 1000);
      plugin.setVerifyCode(aliSmsCache, mobile, code);
    }

    var params = {
      RegionId: settings.regionId || "cn-hangzhou",
      PhoneNumbers: mobile,
      SignName: settings.signName,
      TemplateCode: settings.templateCode,
      TemplateParam: `{${settings.templateParam}:${code}}`
    };

    var requestOption = {
      method: "POST"
    };

    client.request("SendSms", params, requestOption).then(
      result => {
        console.log(JSON.stringify(result));
        res.json({ error: false, info: "验证码已发送" });
      },
      ex => {
        console.log(ex);
        res.json({ error: true, info: "验证码发送失败" });
      }
    );
  });
};

plugin.init = function(data, callback) {
  var hostMiddleware = data.middleware;
  var hostHelpers = require.main.require("./src/routes/helpers");
  var controllers = require("./static/lib/controllers");
  if (!data.app.locals.aliyunsms_verify) {
    data.app.locals.aliyunsms_verify = {};
  }

  function render(req, res, next) {
    res.render("admin/plugins/aliyunsms-verify", {});
  }

  data.router.get(
    "/admin/plugins/aliyunsms-verify",
    data.middleware.admin.buildHeader,
    render
  );
  data.router.get("/api/admin/plugins/aliyunsms-verify", render);

  data.router.post(
    "/api/plugins/aliyunsms-verify/verify",
    loggedIn.ensureLoggedIn(),
    function(req, res) {
      user.isAdministrator(req.session.passport.user, function(err, isAdmin) {
        if (isAdmin !== true && req.session.passport.user != req.body.uid) {
          res.json({ error: true, info: "invalid user" });
          return;
        }
        plugin.getMobiles(function(err, data) {
          const mobile = req.body.mobile;
          if (data.indexOf(mobile) >= 0) {
            res.json({ error: true, info: "手机号已绑定" });
          } else {
            if (!isAdmin) {
              const aliSmsCache = req.app.locals.aliyunsms_verify;
              const code = req.body.code;
              const result = plugin.checkVerifyCode(aliSmsCache, mobile, code);
              if (result.error) {
                res.json(result);
                return;
              }
            }
            const uid = req.body.uid;
            db.setObjectField(
              "aliyunsms-verify:uid:mobile",
              uid,
              mobile,
              function(err) {
                if (err == null) {
                  user.setUserField(uid, "email:confirmed", 1);
                  db.sortedSetRemove("users:notvalidated", uid);
                  log.info("User " + uid + " now associated with " + mobile);
                  res.json({ error: false, info: "手机绑定成功" });
                } else {
                  log.warn("DB Error " + err);
                  res.json({ error: true, info: "DB Error" });
                }
              }
            );
          }
        });
      });
    }
  );

  data.router.post(
    "/api/plugins/aliyunsms-verify/getCode",
    // loggedIn.ensureLoggedIn(),
    function(req, res) {
      // user.isAdministrator(req.session.passport.user, function(err, isAdmin) {
      //   if (isAdmin !== true && req.session.passport.user != req.body.uid) {
      //     res.json({ error: true, info: "invalid user" });
      //     return;
      //   }
      if (!req.body.mobile) {
        res.json({ error: true, info: "手机号已绑定" });
        return;
      }
      plugin.getMobiles(function(err, data) {
        if (data.indexOf(req.body.mobile) >= 0) {
          res.json({ error: true, info: "手机号已绑定" });
        } else {
          plugin.sentVerifySms(req, res);
        }
      });
      // });
    }
  );

  hostHelpers.setupPageRoute(
    data.router,
    "/user/:userslug/aliyunsms",
    hostMiddleware,
    [hostMiddleware.canViewUsers, hostMiddleware.checkAccountPermissions],
    controllers.renderSettings
  );
  callback();
};

plugin.updateTitle = function(data, callback) {
  if (data.templateData.url.match(/user\/.+\/mobile/)) {
    data.templateData.title = "绑定手机";
  }
  callback(null, data);
};

plugin.addMenuItem = function(custom_header, callback) {
  custom_header.plugins.push({
    route: "/plugins/aliyunsms-verify",
    icon: "fa-microphone",
    name: "bind mobile by aliyunsms"
  });

  callback(null, custom_header);
};

plugin.editAccount = function(data, callback) {
  data.editButtons.push({
    link: "/user/" + data.userslug + "/aliyunsms",
    text: "绑定手机"
  });

  callback(null, data);
};

plugin.getUidByUserslug = function(uid, callback) {
  user.getUidByUserslug(uid, callback);
};

plugin.get = function(uid, callback) {
  db.getObjectField("aliyunsms-verify:uid:mobile", uid, callback);
};

plugin.isVerified = function(uid, callback) {
  db.isObjectField("aliyunsms-verify:uid:mobile", uid, callback);
};

plugin.getMobiles = function(callback) {
  db.getObjectValues("aliyunsms-verify:uid:mobile", callback);
};

plugin.delete = function(uid, callback) {
  db.deleteObjectField("aliyunsms-verify:uid:mobile", uid, callback);
};

plugin.canSent = function(aliSmsCache, uid, mobile, ip) {
  let userTimes;
  if (uid) {
    const userKey = `uid_${uid}`;
    userTimes = aliSmsCache[userKey] || 0;
  } else {
    userTimes = 0;
  }
  const mobileTimes = aliSmsCache[mobile] || 0;
  const ipTimes = aliSmsCache[ip] || 0;
  return userTimes < 10 && mobileTimes < 10 && ipTimes < 20;
};
plugin.updateUserTimes = function(aliSmsCache, uid) {
  if (uid) {
    const userKey = `uid_${uid}`;
    const userTimes = aliSmsCache[userKey] || 0;
    if (userTimes == 0) {
      aliSmsCache[userKey] = userTimes + 1;
      setTimeout(function() {
        delete aliSmsCache[userKey];
      }, 60 * 60 * 1000);
    } else {
      aliSmsCache[userKey] = userTimes + 1;
    }
  }
};
plugin.updateMobileTimes = function(aliSmsCache, mobile) {
  const mobileTimes = aliSmsCache[mobile] || 0;
  if (mobileTimes == 0) {
    aliSmsCache[mobile] = mobileTimes + 1;
    setTimeout(function() {
      delete aliSmsCache[mobile];
    }, 60 * 60 * 1000);
  } else {
    aliSmsCache[mobile] = mobileTimes + 1;
  }
};
plugin.updateIPTimes = function(aliSmsCache, ip) {
  const ipTimes = aliSmsCache[ip] || 0;
  if (ip_times == 0) {
    aliSmsCache[ip] = ipTimes + 1;
    setTimeout(function() {
      delete aliSmsCache[mobile];
    }, 60 * 60 * 1000);
  } else {
    aliSmsCache[mobile] = ipTimes + 1;
  }
};
plugin.setVerifyCode = function(aliSmsCache, mobile, code) {
  aliSmsCache[mobile + "code"] = `${code}`;
  setTimeout(function() {
    delete aliSmsCache[mobile + "code"];
  }, 60 * 3 * 1000);
};
plugin.checkVerifyCode = function(aliSmsCache, mobile, code) {
  const cacheCode = aliSmsCache[mobile + "code"];
  if (!cacheCode) {
    return { error: true, info: "验证码已过期" };
  }
  if (cacheCode !== code) {
    return { error: true, info: "验证码不正确" };
  }
  return { error: false, info: "验证码正确" };
};
module.exports = plugin;
